home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / amisl090.zip / AMIS.ASM < prev    next >
Assembly Source File  |  1992-09-12  |  19KB  |  699 lines

  1. ;-----------------------------------------------------------------------
  2. ; Alternate Multiplex Interrupt Specification Library
  3. ; AMIS.ASM    Public Domain 1992 Ralf Brown
  4. ;        You may do with this software whatever you want, but
  5. ;        common courtesy dictates that you not remove my name
  6. ;        from it.
  7. ;
  8. ; Version 0.90
  9. ; LastEdit: 9/12/92
  10. ;-----------------------------------------------------------------------
  11.  
  12.     INCLUDE AMIS.MAC
  13.  
  14. TSRcode@
  15. EXTRN $AMIS$HOOKED_INT_LIST:BYTE
  16. EXTRN $AMIS$MULTIPLEX_NUMBER:BYTE
  17. EXTRN ALTMPX$PSP:WORD
  18. TSRcodeEnd@
  19.  
  20. EXTRN __psp:WORD
  21.  
  22. ;-----------------------------------------------------------------------
  23.  
  24. _TEXT SEGMENT PUBLIC BYTE 'CODE'
  25.     ASSUME    CS:_TEXT
  26.  
  27. ;-----------------------------------------------------------------------
  28.  
  29. alloc_strat    dw 0
  30. link_state    db 0    ; are UMBs part of memory chain?
  31. install_flags    db 0    ; mpx_number must immediately follow
  32. mpx_number    db 0    ; multiplex number to install on/when uninstalling
  33.  
  34. ;-----------------------------------------------------------------------
  35. ; Terminate back to DOS.  Depending on where the resident code was moved,
  36. ; the program will be terminated either with a normal terminate call or
  37. ; with a terminate-and-stay-resident call.
  38. ;
  39. public $go_TSR
  40. $go_TSR proc DIST
  41.     db    0BAh        ; MOV    DX,IMM16
  42. resident_size    dw 0        ; number of paras to keep on going TSR
  43.     db    0B8h        ; MOV    AX,IMM16
  44. exit_code    db 0        ; exit_func must immediately follow
  45. exit_func    db 4Ch        ; will change to 31h if we must go resident
  46.     int    21h
  47. $go_TSR endp
  48.  
  49. ;-----------------------------------------------------------------------
  50. ; entry: DX:AX -> TSR signature string
  51. ; exit:     CF clear if not installed
  52. ;        AL = 00h if free multiplex number exists
  53. ;            AH = multiplex number to use
  54. ;           = 01h if all multiplex numbers are already in use
  55. ;            AH destroyed
  56. ;        CX destroyed
  57. ;     CF set if already installed
  58. ;        AL = FFh
  59. ;        AH = multiplex number being used
  60. ;        CX = version number of resident TSR
  61. ;
  62. public check_if_installed
  63. check_if_installed proc DIST
  64.     ASSUME    DS:NOTHING,ES:NOTHING
  65.     push    ds
  66.     push    si
  67.     mov    ds,dx
  68.     ASSUME    DS:NOTHING
  69.     mov    si,ax
  70.     push    es
  71.     push    di
  72.     push    dx
  73.     push    bx
  74.     xor    ax,ax            ; AH=mpx #00h, AL=func 00h (instlchk)
  75.     mov    bx,0001h        ; BH=00h, BL=01h: all mpx numbers in use
  76. chk_installed_loop:
  77.     push    ax
  78.     int    2Dh            ; check if INT 2D/AH=xx is in use
  79.     cmp    al,0FFh            ; multiplex number in use?
  80.     pop    ax
  81.     je    chk_installed_inuse
  82.     or    bl,bl            ; if BL=00h, we've already seen a free mpx
  83.     je    chk_installed_next
  84.     mov    bl,0
  85.     mov    bh,ah
  86.     jmp short chk_installed_next
  87. chk_installed_inuse:
  88.     mov    es,dx
  89.     ASSUME    ES:NOTHING
  90.     push    cx            ; remember version number
  91.     mov    cx,16/2            ; length of signature string
  92.     cld
  93.     push    si            ; remember start of desired signature
  94.     rep    cmpsw            ; did we get our signature?
  95.     pop    si            ; get back start of desired signature
  96.     pop    cx            ; retrieve version
  97.     stc                ; assume already installed
  98.     jz    chk_installed_done    ;   and quit if it is
  99. chk_installed_next:
  100.     inc    ah
  101.     jnz    chk_installed_loop
  102. ; not yet installed
  103.     clc
  104.     mov    ah,bh            ; AH <- multiplex number to use
  105.     mov    al,bl            ; AL <- 'available' flag
  106. chk_installed_done:
  107.     pop    bx
  108.     pop    dx
  109.     pop    di
  110.     pop    es
  111.     pop    si
  112.     pop    ds
  113.     ASSUME    DS:NOTHING,ES:NOTHING
  114.     ret
  115. check_if_installed endp
  116.  
  117. ;-----------------------------------------------------------------------
  118. ; Call the XMS driver to allocate an upper memory block
  119. ;
  120. ; entry: DX = number of paragraphs needed
  121. ; exit:     ZF set if successful
  122. ;         BX = segment address of UMB
  123. ;
  124. alloc_UMB proc near
  125.     mov    ah,10h
  126.     ;; fall through to XMS ;;
  127. alloc_UMB endp
  128.  
  129. ;-----------------------------------------------------------------------
  130. ; Call the XMS driver
  131. ;
  132. ; entry: all registers as needed for XMS call
  133. ; exit:     registers as returned by XMS driver
  134. ;     ZF set if successful, ZF clear if failure
  135. ;
  136. XMS proc near
  137.     db    09Ah    ; FAR CALL
  138. xms_entry dd    0    ; XMS driver's entry point
  139.     cmp    ax,1
  140.     ret
  141. XMS endp
  142.  
  143. ;-----------------------------------------------------------------------
  144. ; Determine entry point of XMS driver and initialize procedure XMS to call
  145. ; that entry point
  146. ;
  147. ; exit: CF set if no XMS driver or other failure
  148. ;    CF clear if initialization successful
  149. ;    AX,BX destroyed
  150. ;
  151. get_XMS_entry proc near
  152.     push    es
  153.     mov    ax,352Fh
  154.     int    21h            ; find out whether INT 2F is valid
  155.     mov    ax,es
  156.     or    ax,bx            ; don't try XMS if INT 2F is NULL
  157.     jz    no_XMS_driver        ; (could be case under DOS 2.x)
  158.     mov    ax,4300h        ; see if XMS is installed
  159.     int    2Fh
  160.     cmp    al,80h            ; did XMS respond?
  161.     jnz    no_XMS_driver
  162.     mov    ax,4310h        ; if XMS present, get its entry point
  163.     int    2Fh
  164.     mov    word ptr xms_entry,bx
  165.     mov    word ptr xms_entry+2,es ; and store entry point for call
  166.     pop    es
  167.     clc
  168.     ret
  169. no_XMS_driver:
  170.     pop    es
  171.     stc
  172.     ret
  173. get_XMS_entry endp
  174.  
  175. ;-----------------------------------------------------------------------
  176. ; Get an Upper Memory Block from the XMS driver; depending on the
  177. ; installation flags, this block will either be the first one available
  178. ; or the one closest in size to the requested amount
  179. ;
  180. ; entry: AX = number of paragraphs needed
  181. ; exit:     AX = segment of UMB or 0000h if unable to allocate one
  182. ;
  183. allocate_UMB proc near
  184.     mov    dx,ax            ; remember amount of memory to alloc
  185.     call    get_XMS_entry
  186.     jc    no_XMS_avail
  187.     test    install_flags,BEST_FIT
  188.     jnz    alloc_bestfit_UMB    ; DX = amount to request
  189. alloc_XMS:
  190.     call    alloc_UMB        ; ask XMS for the memory
  191.     mov    ax,bx            ; (BX -> UMB if successful)
  192.     je    allocate_UMB_done    ; if we got the mem, return now
  193. no_XMS_avail:
  194.     xor    ax,ax            ; return segment 0 if no UMB
  195. allocate_UMB_done:
  196.     ret
  197. allocate_UMB endp
  198.  
  199. alloc_bestfit_UMB proc near
  200.     push    si
  201.     push    di
  202.  @alloc_size = SI
  203.  @umb_addr = DI
  204.     mov    @alloc_size,dx        ; remember how much to request
  205.     mov    dx,0FFFFh        ; try 1 meg
  206.     call    alloc_UMB        ; ask XMS for the memory
  207.     je    XMM_broken        ; if we got it, XMM seriously broken!
  208.     cmp    dx,@alloc_size        ; DX = largest available
  209.     jb    UMB_too_small        ; not enough high memory left
  210.     call    alloc_UMB        ; allocate the largest UMB
  211.     jne    XMM_broken        ; if we didn't get it, XMM broken
  212.     mov    @umb_addr,bx        ; remember UMB address
  213.     mov    dx,@alloc_size
  214.     call    alloc_bestfit_UMB    ; recurse
  215.     or    ax,ax
  216.     jnz    got_block
  217.     mov    ah,11h            ; deallocate UMB
  218.     mov    dx,@umb_addr
  219.     call    XMS
  220.     mov    dx,@alloc_size
  221.     call    alloc_UMB        ; ask XMS driver for the memory
  222.     jne    UMB_too_small        ; did we get it?
  223.     mov    ax,bx            ; BX = addr of UMB
  224.     jmp short alloc_best_done
  225.  
  226. got_block:
  227.     push    ax            ; remember address to return
  228.     mov    ah,11h            ; deallocate UMB
  229.     mov    dx,@umb_addr
  230.     call    XMS
  231.     pop    ax            ; retrieve return value
  232.     jmp short alloc_best_done
  233.  
  234. XMM_broken:
  235. UMB_too_small:
  236.     xor    ax,ax            ; didn't get anything
  237. alloc_best_done:
  238.     pop    di
  239.     pop    si
  240.     ret
  241. alloc_bestfit_UMB endp
  242.  
  243. ;-----------------------------------------------------------------------
  244. ; entry: nothing
  245. ; exit:     CF set if not available, clear if available
  246. ;     AX,BX,CX,DX destroyed
  247. ;     if available, DOS5 UMBs have been linked into the memory chain
  248. ;
  249. check_if_DOS5_UMBs proc near
  250.     mov    ax,5800h
  251.     int    21h            ; get current allocation strategy
  252.     mov    alloc_strat,ax        ;   and remember it for later restore
  253.     mov    ax,5802h        ; get current state of UMB linkage
  254.     int    21h
  255.     mov    link_state,al
  256.     mov    ax,3000h        ; get DOS version
  257.     int    21h
  258.     cmp    al,5            ; DOS 5.0 or higher?
  259.     jb    no_DOS5_UMBs
  260.     cmp    al,10            ; but make sure not OS/2 penalty box
  261.     jae    no_DOS5_UMBs
  262.     mov    ax,2B01h
  263.     mov    cx,4445h
  264.     mov    dx,5351h
  265.     int    21h            ; check if DESQview running
  266.     cmp    al,0FFh            ; if yes, no UMB's to be allocated
  267.     jne    no_DOS5_UMBs
  268.     mov    ax,5803h
  269.     mov    bx,1            ; try to link in UMBs
  270.     int    21h
  271.     mov    ax,5802h        ; get new link state
  272.     int    21h
  273.     cmp    al,1
  274.     jne    no_DOS5_UMBs
  275.     clc                ; yes, we have UMBs
  276.     ret
  277.  
  278. no_DOS5_UMBs:
  279.     stc
  280.     ret
  281. check_if_DOS5_UMBs endp
  282.  
  283. ;-----------------------------------------------------------------------
  284. ;
  285. ; entry: BX = memory allocation strategy
  286. ; exit:     CF set on error
  287. ;     CF clear if successful
  288. ;        AX = segment of memory block
  289. ;
  290. alloc_DOS_highmem proc near
  291.     mov    ax,5801h        ; set allocation strategy
  292.     int    21h
  293.     mov    ah,48h            ; allocate memory
  294.     mov    bx,resident_size    ;   this is how much we need
  295.     int    21h            ; try to allocate the UMB
  296.     pushf                ; remember whether we succeeded
  297.     jc    no_highmem        ; did we succeed?
  298.     push    ax            ; yes, so remember where to relocate
  299.     dec    ax            ; address the MCB for our new memory
  300.     mov    es,ax            ;   block
  301.     inc    ax            ; back to relocation segment
  302.     mov    word ptr es:[1],ax    ; make the memory block own itself
  303.     mov    ah,51h            ; get current PSP
  304.     int    21h
  305.     dec    bx            ; back to MCB for main memory block
  306.     push    ds
  307.     mov    ds,bx            ; point at MCB
  308.     ASSUME    DS:NOTHING
  309.     push    si
  310.     push    di
  311.     mov    si,8
  312.     mov    di,si
  313.     cld
  314.     movsw                ; copy the DOS 4.0+ program name into
  315.     movsw                ;   the new memory block's MCB
  316.     movsw
  317.     movsw
  318.     pop    di
  319.     pop    si
  320.     pop    ds
  321.     ASSUME    DS:NOTHING
  322.     pop    ax            ; retrieve relocation address
  323. ;---------------------------
  324. ; Reasons for mucking with the MCB:
  325. ;    DOS 5 will release any memory blocks owned by the program when
  326. ;    it exits without going TSR, even if the blocks are in high memory
  327. ;    and high memory has been disconnected from the memory chain.  So,
  328. ;    we need to change the owner field such that DOS thinks it belongs to
  329. ;    somebody else and doesn't release it when we exit.
  330. ;---------------------------
  331. no_highmem:
  332.     popf                ; get back whether we were successful
  333. restore_link_state:
  334.     pushf                ; store flags, especially CF
  335.     push    ax
  336.     mov    ax,5801h
  337.     mov    bx,alloc_strat        ; restore allocation strategy
  338.     int    21h
  339.     mov    ax,5803h        ; and restore UMB link status
  340.     mov    bh,0
  341.     mov    bl,link_state
  342.     int    21h
  343.     pop    ax
  344.     popf                ; get back flags
  345.     ret
  346. alloc_DOS_highmem endp
  347.  
  348. ;-----------------------------------------------------------------------
  349. ; entry: AL = flags
  350. ;        bit 0 = use first-fit alloc, nonzero = use best-fit alloc
  351. ;        bit 1 = use UMB only, never conventional memory
  352. ;        bit 2 = use low 640K only even if UMB available
  353. ;        bit 3 = use top of lower memory (at 640K)
  354. ;        bit 7 = patch resident portion's PSP return value
  355. ;     AH = multiplex number
  356. ;     BX = segment of resident code
  357. ;     CX = size of resident code in paragraphs
  358. ;     DX = additional paragraphs
  359. ; exit:     CF clear if successful
  360. ;         AX = segment at which TSR was installed
  361. ;     CF set on error
  362. ;
  363. public $install_TSR
  364. $install_TSR proc DIST
  365.     push    es
  366.     push    si
  367.     push    di
  368.     mov    word ptr install_flags,ax ; set both install_flags & mpx_number
  369.     push    bx            ; remember segment of resident code
  370.     push    cx            ; remember size of resident code
  371.     mov    ax,cx
  372.     add    ax,dx
  373.     mov    resident_size,ax
  374.  ;
  375.  ; first, see if we can load into a DOS5 UMB (this is preferred because
  376.  ; 386MAX will give us an XMS UMB even if DOS5 has grabbed them, but at
  377.  ; a cost of an extra 80 bytes of overhead).
  378.  ;
  379.      test    install_flags,LOW_ONLY
  380.     jnz    not_XMS
  381.     call    check_if_DOS5_UMBs    ; check if UMBs avail, and link them in
  382.     jc    not_dos5
  383.     mov    bx,40h            ; alloc high memory only, first-fit
  384.     test    install_flags,BEST_FIT
  385.     jz    go_allocate_DOS_highmem
  386.     inc    bx            ; BX <- 41h = alloc high only, best-fit
  387. go_allocate_DOS_highmem:
  388.     call    alloc_DOS_highmem
  389.     jnc    relocate_TSR_code    ; if successful, go install
  390.  ;
  391.  ; if not DOS5, see if we can load into an XMS upper memory block
  392.  ;
  393. not_dos5:
  394.     mov    ax,resident_size
  395.     call    allocate_UMB        ; try to get AX paragraphs
  396.     or    ax,ax            ; did we get a UMB?
  397.     jnz    relocate_TSR_code    ; if yes, go install at segment AX
  398.  
  399.  ;
  400.  ; if not XMS, see whether we are allowed to load into conventional memory;
  401.  ; if yes, check whether we are supposed to load at the high or low end of
  402.  ; conventional memory
  403.  ;
  404. not_XMS:
  405.     test    install_flags,UMB_ONLY
  406.     jnz    install_failure
  407. install_low:
  408.     test    install_flags,USE_TOPMEM
  409.     jz    not_topmem
  410.     mov    bx,2            ; last-fit in low memory
  411.     call    alloc_DOS_highmem    ; try to allocate at top of memory
  412.     jnc    relocate_TSR_code    ; and go install
  413. install_failure:
  414.     pop    cx            ; clean up stack
  415.     pop    bx
  416.     jmp    install_failed
  417.  ;
  418.  ; as a last resort, use our own PSP to store the code, and go resident
  419.  ;
  420. not_topmem:
  421.     mov    ax,__psp
  422.     mov    es,ax
  423.     add    ax,4            ; copy to offset 40h in PSP
  424.     push    ax            ; remember where we'll relocate
  425.     add    resident_size,4
  426.     mov    exit_func,31h        ; TSR rather than normal exit
  427.     xor    ax,ax
  428.     xchg    ax,es:[002Ch]        ; get and zero environment segment
  429.     mov    es,ax
  430.     mov    ah,49h            ; since we will be going resident,
  431.     int    21h            ;   discard our environment
  432.     pop    ax            ; get back destination segment
  433.  ;
  434.  ; relocate TSR code into the PSP or UMB
  435.  ; at this point, AX must be the segment at which to relocate
  436.  ;
  437. relocate_TSR_code:
  438.     pop    cx            ; get back TSR code size in paragraphs
  439.     pop    bx            ; get back TSR code segment
  440.     push    ds
  441.     mov    ds,bx
  442.     ASSUME    DS:NOTHING
  443.     mov    es,ax            ; ES -> resident_seg
  444.     ASSUME    ES:NOTHING
  445.     xor    si,si
  446.     xor    di,di
  447.     mov    ax,16            ; bytes per paragraph
  448.     mul    cx            ; get size in bytes
  449.     or    dx,dx
  450.     jnz    install_failed_pop    ; can only handle 64K at this time
  451.     mov    cx,ax            ; number of bytes to copy
  452.     cld
  453.     rep    movsb            ; copy the TSR's code
  454.     mov    al,mpx_number        ; patch the multiplex number in the
  455.     mov    es:[$AMIS$MULTIPLEX_NUMBER],al ;  resident code
  456.     test    install_flags,PATCH_RESIDENT
  457.     jz    install_no_patch
  458.     mov    ax,es            ; AX <- resident_seg
  459.     cmp    exit_func,4Ch
  460.     je    install_patch
  461.     pop    ds            ; restore DS
  462.     mov    ax,__psp
  463.     push    ds            ; need DS on stack
  464. install_patch:
  465.     mov    word ptr es:[ALTMPX$PSP],ax
  466. install_no_patch:
  467.     push    es            ; remember resident segment
  468.     push    es
  469.     pop    ds            ; DS -> resident_seg
  470.     mov    si,offset RESIDENT_CODE:$AMIS$HOOKED_INT_LIST
  471. hook_interrupts:
  472.     lodsb                ; get interrupt number
  473.     mov    ah,35h            ; get interrupt vector
  474.     int    21h
  475.     mov    dx,bx            ; ES:DX -> prev handler
  476.     mov    bx,[si]            ; get offset of interrupt handler
  477.     inc    si
  478.     inc    si
  479.     mov    [bx+2],dx        ; set 'previous' pointer in ISP header
  480.     mov    [bx+4],es
  481.     mov    dx,bx            ; DS:DX -> our handler
  482.     mov    ah,25h            ; AL still interrupt number
  483.     int    21h            ; hook the interrupt
  484.     cmp    al,2Dh            ; INT 2Dh is last in hook list
  485.     jne    hook_interrupts
  486.     pop    ax            ; AX <- resident_seg
  487.     pop    ds
  488. ;    clc                ; we were successful ;(CF already clear)
  489. install_TSR_done:
  490.     pop    di
  491.     pop    si
  492.     pop    es
  493.     ret
  494.  
  495. install_failed_pop:
  496.     pop    ds
  497. install_failed:
  498.     stc                ; signal installation failure
  499.     jmp    install_TSR_done
  500. $install_TSR endp
  501.  
  502. ;-----------------------------------------------------------------------
  503. ; entry: DS:SI -> hooked interrupt list
  504. ; exit:     AX, BX, CX, DX destroyed
  505. ;     CF set if unable to unhook all vectors
  506. ;     CF clear if successful
  507. ;
  508. public unhook_interrupts
  509. unhook_interrupts proc DIST
  510.     push    es
  511.     push    ds
  512.     push    di
  513.     push    si
  514.     cld
  515. chk_unhook_loop:
  516.     lodsb
  517.     mov    dx,[si]            ; get offset of interrupt handler
  518.     inc    si            ;   and skip that field in the hook
  519.     inc    si            ;   list
  520.     cmp    al,2Dh
  521.     je    all_unhookable
  522.     mov    ah,35h
  523.     int    21h            ; get interrupt vector
  524.     mov    ax,es
  525.     mov    cx,ds
  526.     cmp    ax,cx            ; check segment agains of vectors
  527.     jne    chk_isp_loop
  528.     cmp    dx,bx            ; check offset of vector against ours
  529.     je    chk_unhook_loop        ; this int is unhookable if same
  530. chk_isp_loop:
  531.     cmp    word ptr es:[bx],10EBh    ; handler starts with JMP SHORT $+12 ?
  532.     jne    not_unhookable
  533.     cmp    word ptr es:[bx+6],424Bh ; valid signature?
  534.     jne    not_unhookable
  535.     cmp    byte ptr es:[bx+9],0EBh ; hardware reset must also be JMP SHORT
  536.     jne    not_unhookable
  537.     cmp    cx,word ptr es:[bx+4]    ; check segment of next ptr against ours
  538.     jne    chk_next_isp
  539.     cmp    dx,word ptr es:[bx+2]    ; check offset of next ptr against ours
  540.     je    chk_unhook_loop        ; this int is unhookable if same
  541. chk_next_isp:
  542.     les    bx,es:[bx+2]        ; advance to next ISP header
  543.     jmp    chk_isp_loop        ;   and test it
  544.  
  545. not_unhookable:
  546.     stc
  547. unhook_ints_done:
  548.     pop    di
  549.     pop    si
  550.     pop    ds
  551.     pop    es
  552.     ret
  553.  
  554. all_unhookable:
  555.     pop    si            ; get back start of hook list
  556.     push    si            ; and preserve SI for return
  557. unhook_loop:
  558.     lodsb
  559.     mov    dx,[si]
  560.     inc    si
  561.     inc    si
  562.     push    ds
  563.     push    ax
  564.     mov    ah,35h
  565.     int    21h            ; get interrupt vector
  566.     mov    ax,es
  567.     mov    cx,ds
  568.     cmp    ax,cx            ; check segments of vectors
  569.     jne    isp_loop
  570.     cmp    dx,bx            ; check offsets of vectors
  571.     jne    isp_loop
  572.     lds    dx,[bx+2]        ; get our old_int?? pointer
  573.     pop    ax
  574.     push    ax
  575.     mov    ah,25h            ; set interrupt vector
  576.     int    21h
  577.     jmp short unhooked_interrupt
  578. isp_next:
  579.     les    bx,es:[bx+2]        ; advance to next ISP header
  580. isp_loop:
  581. ;
  582. ; no need to check for a valid ISP header, as we already know all chains reach
  583. ; our header before non-ISP code
  584. ;
  585.     cmp    cx,es:[bx+4]        ; check segment of 'previous' ptr
  586.     jne    isp_next
  587.     cmp    dx,es:[bx+2]        ; check offset of 'previous' ptr
  588.     jne    isp_next
  589.     xchg    bx,dx
  590.     lds    bx,[bx+2]
  591.     xchg    bx,dx            ; ES:BX -> previous ISP
  592.                     ; DS:DX -> next ISP
  593.     mov    es:[bx+2],dx        ; prev->next = curr->next
  594.     mov    es:[bx+4],ds        ;    thus, we are now unhooked
  595. unhooked_interrupt:
  596.     pop    ax
  597.     pop    ds
  598.     cmp    al,2Dh
  599.     jne    unhook_loop
  600.     clc                ; indicate success
  601.     jmp    unhook_ints_done
  602. unhook_interrupts endp
  603.  
  604. ;-----------------------------------------------------------------------
  605. ; entry: DX:AX -> TSR signature string
  606. ; exit:     CF clear if successful
  607. ;     CF set on error
  608. ;     AX,BX,CX,DX destroyed
  609. ;
  610. public $uninstall_TSR
  611. $uninstall_TSR proc DIST
  612.     push    es
  613.     call    check_if_installed
  614.     jnc    not_installed
  615.     ;
  616.     ; TSR is installed, AH=multiplex number
  617.     ;
  618.     mov    mpx_number,ah
  619.     ;
  620.     ; first, see whether the TSR can uninstall itself
  621.     ;
  622.     mov    al,2
  623.     mov    dx,cs            ; load return address for success
  624.     mov    bx,offset _TEXT:uninstall_successful
  625.     int    2Dh
  626.     cmp    al,0FFh            ; successful?
  627.     je    uninstall_successful
  628.     cmp    al,02h            ; will uninstall itself
  629.     je    uninstall_successful
  630.     cmp    al,01h            ; unable to remove at this time?
  631.     je    uninstall_failed
  632.     cmp    al,05h            ; unknown return code?
  633.     jae    uninstall_failed
  634.     ;
  635.     ; TSR said it is safe to uninstall, but not able to do so itself,
  636.     ; so now we find out which interrupts it has hooked
  637.     ;
  638.     mov    es,bx            ; point ES at memory block to be freed
  639.     ASSUME    ES:NOTHING
  640. uninst_chk_int_loop:
  641.     mov    ah,mpx_number
  642.     mov    al,4
  643.     mov    bl,0            ; start with INT 00h
  644.     int    2Dh
  645.     cmp    al,1            ; function unsupported or can't determine?
  646.     jbe    uninstall_failed
  647.     cmp    al,4
  648.     je    go_uninstall
  649.  
  650. ;    jmp short uninstall_failed    ; sorry, can't handle returns 02h/03h yet
  651. uninstall_failed:
  652. not_installed:
  653.     pop    es            ; clean up stack
  654.     stc                ; indicate error
  655.     ret
  656.  
  657. go_uninstall:
  658.     push    ds
  659.     push    si
  660.     mov    ds,dx            ; DS:SI -> hook list
  661.     mov    si,bx
  662.     call    unhook_interrupts
  663.     pop    si
  664.     pop    ds
  665.     jc    uninstall_failed
  666.     mov    ax,es            ; get segment of memory block
  667.     cmp    ax,0B000h        ; regular DOS memblk if below video
  668.     jae    uninstall_highmem
  669.     mov    ah,49h            ; free memory block
  670.     int    21h
  671. uninstall_successful:
  672.     pop    es            ; clean up stack
  673.     clc                ; indicate success
  674.     ret
  675.  
  676. uninstall_highmem:
  677.     call    check_if_DOS5_UMBs    ; check if UMBs, and link them in
  678.     jc    uninstall_XMS
  679.     mov    ah,49h            ; free the memory block via DOS
  680.     int    21h            ;   (ES already points at block)
  681.     call    restore_link_state
  682.     jmp    uninstall_successful
  683.  
  684. uninstall_XMS:
  685.     call    get_XMS_entry
  686.     jc    uninstall_failed    ; no XMS driver!?!?!
  687.     mov    ah,11h            ; release UMB
  688.     mov    dx,es            ; set DX to UMB segment
  689.     call    XMS
  690.     jne    uninstall_failed    ; we deallocation successful?
  691.     jmp    uninstall_successful
  692. $uninstall_TSR endp
  693.  
  694. ;-----------------------------------------------------------------------
  695.  
  696. _TEXT ENDS
  697.     END
  698.  
  699.